# 更新时间：2025年9月24日 20:33:49 亲测可用
import os
import re
import tkinter as tk
from tkinter import simpledialog, filedialog, messagebox

def get_user_input():
    """获取用户输入的目录和标签信息"""
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口
    root.title("Markdown标签更新工具")
    
    # 选择目录
    directory = filedialog.askdirectory(title="选择包含Markdown文件的目录")
    if not directory:
        return None, None, None
    
    # 输入要修改的标签
    old_tag = simpledialog.askstring("输入标签", "请输入要修改的标签:")
    if not old_tag:
        return directory, None, None
    
    # 输入新的标签
    new_tag = simpledialog.askstring("输入新标签", f"请将标签 '{old_tag}' 修改为:")
    if not new_tag:
        return directory, old_tag, None
    
    return directory, old_tag.strip(), new_tag.strip()

def extract_front_matter(content):
    """从Markdown内容中提取front matter"""
    front_matter = {}
    has_front_matter = False
    remaining_content = content
    
    if content.startswith('---'):
        end_index = content.find('---', 3)
        if end_index != -1:
            has_front_matter = True
            front_matter_text = content[3:end_index].strip()
            remaining_content = content[end_index+3:].lstrip()
            
            # 解析front matter
            lines = front_matter_text.split('\n')
            current_key = None
            current_value = []
            
            for line in lines:
                line = line.rstrip()
                if not line:
                    continue
                    
                # 检查是否是新的键值对
                if ':' in line and not line.startswith(' '):
                    # 保存前一个键值对
                    if current_key is not None:
                        front_matter[current_key] = '\n'.join(current_value).strip()
                    
                    # 开始新的键值对
                    key, value = line.split(':', 1)
                    current_key = key.strip()
                    current_value = [value.strip()]
                else:
                    # 继续当前键的值
                    if current_key is not None:
                        current_value.append(line)
            
            # 保存最后一个键值对
            if current_key is not None:
                front_matter[current_key] = '\n'.join(current_value).strip()
    
    return front_matter, remaining_content, has_front_matter

def parse_tags(tags_value):
    """解析tags字段，返回标签列表"""
    if not tags_value:
        return []
    
    tags_value = tags_value.strip()
    
    # 处理列表格式 [tag1, tag2, tag3]
    if tags_value.startswith('[') and tags_value.endswith(']'):
        tags_str = tags_value[1:-1]
        tags = []
        # 处理引号包围的标签
        in_quote = False
        current_tag = ''
        quote_char = None
        
        for char in tags_str:
            if char in ['"', "'"] and not in_quote:
                in_quote = True
                quote_char = char
            elif char == quote_char and in_quote:
                in_quote = False
                if current_tag:
                    tags.append(current_tag)
                    current_tag = ''
            elif char == ',' and not in_quote:
                if current_tag.strip():
                    tags.append(current_tag.strip())
                    current_tag = ''
            else:
                current_tag += char
        
        if current_tag.strip():
            tags.append(current_tag.strip())
        
        return [tag.strip() for tag in tags if tag.strip()]
    
    # 处理空格分隔的标签
    else:
        # 处理引号包围的标签
        tags = []
        in_quote = False
        current_tag = ''
        quote_char = None
        
        for char in tags_value:
            if char in ['"', "'"] and not in_quote:
                in_quote = True
                quote_char = char
            elif char == quote_char and in_quote:
                in_quote = False
                tags.append(current_tag)
                current_tag = ''
            elif char.isspace() and not in_quote:
                if current_tag:
                    tags.append(current_tag)
                    current_tag = ''
            else:
                current_tag += char
        
        if current_tag:
            tags.append(current_tag)
        
        return [tag.strip() for tag in tags if tag.strip()]

def format_tags(tags_list):
    """将标签列表格式化为YAML格式"""
    if not tags_list:
        return "[]"
    
    # 使用引号包围每个标签，避免特殊字符问题
    formatted_tags = ', '.join([f'"{tag}"' for tag in tags_list])
    return f'[{formatted_tags}]'

def update_tags_in_file(file_path, old_tag, new_tag):
    """更新单个Markdown文件的标签"""
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
    except Exception as e:
        print(f"读取文件 {file_path} 时出错: {e}")
        return False, "读取失败"
    
    front_matter, remaining_content, has_front_matter = extract_front_matter(content)
    
    # 检查是否有tags字段
    tags_value = front_matter.get('tags', '')
    original_tags = parse_tags(tags_value)
    
    # 检查旧标签是否存在
    if old_tag not in original_tags:
        return False, f"标签 '{old_tag}' 不存在"
    
    # 检查新标签是否已存在（避免重复）
    if new_tag in original_tags:
        return False, f"新标签 '{new_tag}' 已存在"
    
    # 更新标签
    updated_tags = []
    tag_updated = False
    
    for tag in original_tags:
        if tag == old_tag:
            updated_tags.append(new_tag)
            tag_updated = True
        else:
            updated_tags.append(tag)
    
    if not tag_updated:
        return False, f"未找到标签 '{old_tag}'"
    
    # 更新front matter中的tags字段
    front_matter['tags'] = format_tags(updated_tags)
    
    # 重新构建文件内容
    if has_front_matter:
        # 有front matter的情况
        front_matter_lines = ['---']
        for key, value in front_matter.items():
            if key == 'tags':
                front_matter_lines.append(f'tags: {value}')
            else:
                # 处理多行值
                if '\n' in value:
                    front_matter_lines.append(f'{key}: |')
                    for line in value.split('\n'):
                        front_matter_lines.append(f'  {line}')
                else:
                    front_matter_lines.append(f'{key}: {value}')
        front_matter_lines.append('---')
        new_content = '\n'.join(front_matter_lines) + '\n\n' + remaining_content
    else:
        # 没有front matter的情况，创建新的front matter
        front_matter_lines = [
            '---',
            f'tags: {format_tags(updated_tags)}',
            '---',
            ''
        ]
        new_content = '\n'.join(front_matter_lines) + content
    
    # 写回文件
    try:
        with open(file_path, 'w', encoding='utf-8') as f:
            f.write(new_content)
        return True, f"成功将 '{old_tag}' 修改为 '{new_tag}'"
    except Exception as e:
        print(f"写入文件 {file_path} 时出错: {e}")
        return False, f"写入失败: {e}"

def process_markdown_files(directory, old_tag, new_tag):
    """处理目录中的所有Markdown文件"""
    if not old_tag or not new_tag:
        print("标签信息不完整，退出")
        return
    
    if old_tag == new_tag:
        print("修改前和修改后的标签相同，退出")
        return
    
    md_files = []
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.lower().endswith(('.md', '.markdown')):
                md_files.append(os.path.join(root, file))
    
    if not md_files:
        print(f"在目录 {directory} 中未找到Markdown文件")
        return
    
    print(f"找到 {len(md_files)} 个Markdown文件")
    print(f"将标签 '{old_tag}' 修改为 '{new_tag}'")
    print("=" * 50)
    
    success_count = 0
    skipped_count = 0
    error_count = 0
    results = []
    
    for i, file_path in enumerate(md_files, 1):
        print(f"处理文件 {i}/{len(md_files)}: {os.path.basename(file_path)}")
        
        success, message = update_tags_in_file(file_path, old_tag, new_tag)
        
        if success:
            success_count += 1
            results.append(f"✓ {os.path.basename(file_path)}: {message}")
            print(f"  ✓ {message}")
        elif "不存在" in message or "已存在" in message:
            skipped_count += 1
            results.append(f"○ {os.path.basename(file_path)}: {message}")
            print(f"  ○ {message}")
        else:
            error_count += 1
            results.append(f"✗ {os.path.basename(file_path)}: {message}")
            print(f"  ✗ {message}")
    
    # 显示处理结果
    print("=" * 50)
    print(f"处理完成:")
    print(f"  ✓ 成功: {success_count} 个文件")
    print(f"  ○ 跳过: {skipped_count} 个文件")
    print(f"  ✗ 错误: {error_count} 个文件")
    
    return results, success_count, skipped_count, error_count

def show_results(results, success_count, skipped_count, error_count, old_tag, new_tag):
    """显示处理结果对话框"""
    root = tk.Tk()
    root.withdraw()
    
    result_text = f"标签更新完成!\n\n"
    result_text += f"将标签 '{old_tag}' 修改为 '{new_tag}'\n\n"
    result_text += f"✓ 成功: {success_count} 个文件\n"
    result_text += f"○ 跳过: {skipped_count} 个文件\n"
    result_text += f"✗ 错误: {error_count} 个文件"
    
    if error_count > 0 or success_count > 0:
        # 显示详细结果
        detail_text = "\n".join(results[-20:])  # 显示最后20条结果
        if len(results) > 20:
            detail_text = f"...（显示最后20条，共{len(results)}条）\n" + detail_text
        
        messagebox.showinfo("处理完成", result_text)
        
        # 创建详细结果窗口
        detail_window = tk.Toplevel()
        detail_window.title("详细处理结果")
        detail_window.geometry("800x600")
        
        text_widget = tk.Text(detail_window, wrap=tk.WORD)
        text_widget.insert(tk.END, detail_text)
        text_widget.config(state=tk.DISABLED)
        
        scrollbar = tk.Scrollbar(detail_window, command=text_widget.yview)
        text_widget.config(yscrollcommand=scrollbar.set)
        
        text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    else:
        messagebox.showinfo("处理完成", result_text)

def main():
    """主函数"""
    directory, old_tag, new_tag = get_user_input()
    
    if not directory:
        print("未选择目录，退出")
        return
    
    if not old_tag:
        print("未指定要修改的标签，退出")
        return
    
    if not new_tag:
        print("未指定新标签，退出")
        return
    
    if old_tag == new_tag:
        root = tk.Tk()
        root.withdraw()
        messagebox.showwarning("警告", "修改前和修改后的标签相同，无需修改")
        return
    
    results, success_count, skipped_count, error_count = process_markdown_files(directory, old_tag, new_tag)
    
    # 显示结果
    root = tk.Tk()
    root.withdraw()
    show_results(results, success_count, skipped_count, error_count, old_tag, new_tag)

if __name__ == "__main__":
    main()